package com.vecspace.dayu.code.source.model;

import com.vecspace.dayu.code.consts.TableRelationSubtype;
import com.vecspace.dayu.code.consts.TablesRelation;
import com.vecspace.dayu.code.pojo.DataTable;
import com.vecspace.dayu.code.pojo.Func;
import com.vecspace.dayu.code.pojo.Project;
import com.vecspace.dayu.code.ui.model.PageConfigVO;
import com.vecspace.exception.HException;
import com.vecspace.utils.Assert;
import com.vecspace.utils.Convert;
import com.vecspace.utils.DateTimeUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**和代码模板配套的参数
 * 
 * @version 1.0
 * @author wanghua
 * @reviewer  
 * @createTime 2021年9月18日
 */
public class SourceCodeParams {

	/**主表格*/
	SourceCodeParamsBaseTable mainTableConfig;
	
	/**目录表*/
	SourceCodeParamsBaseTable catalogTableConfig;
	/**叶子表*/
	SourceCodeParamsBaseTable leafTableConfig;
	/**从表*/
	final List<SourceCodeParamsBaseTable> slaveTablesConfig = new ArrayList<>();

	/** 数据表级的模板参数*/
	final List<SourceCodeParamsBaseTable> sourceCodeParams = new ArrayList<>();

	private Project project;
	private Func func;
	//private String terminalType;
	private String author;
	private String nowTime;
	private String sysName;

	private List<DataTable> tables;
	private List<PageConfigVO> tablesConfig;

	/**检查参数是否合理，如有不合理的地方，会抛出异常
	 * @author wanghua
	 */
	public void checkParams() throws Exception{
		for(DataTable table : tables){
			Assert.throwz(table.getIdColumn() != null, String.format("表%s必须指定ID字段", table.getTableName()));
		}
		//检查参数配置是否合理，不合理则抛出异常
		for(SourceCodeParamsBaseTable sourceCodeParam : sourceCodeParams) {
			sourceCodeParam.checkConfig();
		}
	}

	/**
	 *
	 * @param author
	 * @param project
	 * @param func
	 * @param tables
	 * @param tablesConfig
	 * @author Administrator
	 * @date 2021/11/3  13:07
	 * @return void
	 **/
	public void initParams(String author, Project project, Func func, List<DataTable> tables, List<PageConfigVO> tablesConfig){
		this.setProject(project);
		this.setFunc(func);
		this.setAuthor(author);
		String sysName = project.getCode();
		Assert.throwz(StringUtils.isNotBlank(sysName), "project.code不能为空");
		sysName = sysName.trim().toLowerCase();
		setNowTime(DateTimeUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
		setSysName(sysName);

		this.tables = tables;
		this.tablesConfig = tablesConfig;

		buildSourceCodeParams();
	}

	private void buildSourceCodeParams(){
		Assert.throwz(project != null, "SourceCodeParams.project不能为空");
		Assert.throwz(func != null, "SourceCodeParams.func不能为空");
		Assert.throwz(tables != null, "initParamsByTaleConfig.tables不能为空");
		Assert.throwz(tablesConfig != null, "initParamsByTaleConfig.tableConfig不能为空");

		/**主表格*/
		PageConfigVO mainTableConfig = null;
//		/**主表的主表*/
//		PageConfigVO parentTableConfig = null;
		/**从表*/
		final List<PageConfigVO> slaveTablesConfig = new ArrayList<>();
		/**目录表*/
		PageConfigVO catalogTableConfig = null;
		/**叶子表*/
		PageConfigVO leafTableConfig = null;

		for(DataTable table : tables){
			PageConfigVO tableConfig = tablesConfig.stream().filter(it->table.getId().equals(it.getTableId())).findAny().orElse(null);
			if(tableConfig != null) {
				tableConfig.setTable(table);
			}

			String subtype = table.getTableRelationSubtype();
			if(TableRelationSubtype.MasterTable.equals(subtype)){
				mainTableConfig = tableConfig;
			}else if(TableRelationSubtype.SlaveTable.equals(subtype)){
				if(tableConfig != null) {
					tableConfig.setTable(table);
				}
				slaveTablesConfig.add(tableConfig);
			}else if(TableRelationSubtype.CatalogTable.equals(subtype)){
				catalogTableConfig = tableConfig;
			}else if(TableRelationSubtype.LeafTable.equals(subtype)){
				leafTableConfig = tableConfig;
			}else{
				throw new HException(String.format("不能识别的表关系类型 %s(Subtype): %s：", table.getTableName(),subtype));
			}
			
			if(Convert.toBoolean(table.getRecursion(), false) == true) {
				if(table.getParentColumn() == null) {
					throw new HException(String.format("表%s设置为了递归模式，因此必须指定父ID字段：", table.getTableName()));
				}
			}
			if(table.getParentColumn() != null) {
				if(Convert.toBoolean(table.getRecursion(), false) == false) {
					throw new HException(String.format("表%s设置为了父ID字段，因此必须设定为递归模式：", table.getTableName()));
				}
			}
		}

		String tablesRelation = func.getTablesRelation();
		if(TablesRelation.SingleTable.equals(tablesRelation)){//单表结构
			Assert.throwz(mainTableConfig != null, String.format("mainTableConfig不能为空。必须存在Subtype=%s 的数据表", TableRelationSubtype.MasterTableCaption));
			DataTable mainTable = mainTableConfig.getTable();
			if(mainTable.getForeignColumn() != null) {
				Assert.throwz(mainTable.getForeignTable() != null, String.format("表 %s 设置了外键字段，因此外键表不能为空", mainTable.getTableName()));
			}
			SourceCodeParamsBaseTable sourceCodeParam = new SourceCodeParamsBaseTable();
			sourceCodeParam.setTable(mainTable);
			sourceCodeParam.setColumns(mainTableConfig.getColumnVOList());
			sourceCodeParam.setDataGrid(mainTableConfig.getDataGrid());
			sourceCodeParam.setForm(mainTableConfig.getForm());
			sourceCodeParam.setColumns(mainTableConfig.getColumnVOList());
			sourceCodeParam.setParentColumn(mainTable.getParentColumn());
			sourceCodeParam.setForeignColumn(mainTable.getForeignColumn());
			sourceCodeParam.setForeignTable(mainTable.getForeignTable());
			
			sourceCodeParam.setLeafTable(null);
			sourceCodeParam.setUseRecurseQuery(mainTableConfig.getDataGrid().getUseRecurseQuery());
			sourceCodeParam.setIsTree(mainTable.getRecursion());

			this.mainTableConfig = sourceCodeParam;
			sourceCodeParams.add(sourceCodeParam);
		}else if(TablesRelation.CatalogAndLeaf.equals(tablesRelation)){//目录+叶子表结构
			Assert.throwz(catalogTableConfig != null, String.format("表关系为 目录+叶子 时，必须存在 Subtype=%s 的数据表", TableRelationSubtype.CatalogTableCaption));
			Assert.throwz(leafTableConfig != null, String.format("表关系为 目录+叶子 时，必须存在 Subtype=%s 的数据表", TableRelationSubtype.LeafTableCaption));

			DataTable catalogTable = catalogTableConfig.getTable();
			DataTable leafTable = leafTableConfig.getTable();

			if(catalogTable.getForeignColumn() != null) {
				Assert.throwz(catalogTable.getForeignTable() != null, String.format("表 %s 设置了外键字段，因此外键表不能为空", catalogTable.getTableName()));
			}
			Assert.throwz(leafTable.getForeignColumn() != null, String.format("叶子表 %s 的外键字段（关联目录表的字段）不能为空",leafTable.getTableName()));

			
			//目录表
			SourceCodeParamsBaseTable sourceCodeParamCatalog = new SourceCodeParamsBaseTable();
			sourceCodeParamCatalog.setTable(catalogTableConfig.getTable());
			sourceCodeParamCatalog.setColumns(catalogTableConfig.getColumnVOList());
			sourceCodeParamCatalog.setDataGrid(catalogTableConfig.getDataGrid());
			sourceCodeParamCatalog.setForm(catalogTableConfig.getForm());
			sourceCodeParamCatalog.setColumns(catalogTableConfig.getColumnVOList());

			sourceCodeParamCatalog.setParentColumn(catalogTable.getParentColumn());
			sourceCodeParamCatalog.setForeignColumn(catalogTable.getForeignColumn());
			sourceCodeParamCatalog.setForeignTable(catalogTable.getForeignTable());
			
			sourceCodeParamCatalog.setLeafTable(leafTable);
			sourceCodeParamCatalog.setUseRecurseQuery(false);
			sourceCodeParamCatalog.setIsTree(true);

			sourceCodeParamCatalog.setShowLeaf(catalogTableConfig.getDataTree().getShowLeafNode());

			this.mainTableConfig = sourceCodeParamCatalog;
			this.catalogTableConfig = sourceCodeParamCatalog;
			sourceCodeParams.add(sourceCodeParamCatalog);

			//叶子表
			SourceCodeParamsBaseTable sourceCodeParamLeaf = new SourceCodeParamsBaseTable();
			sourceCodeParamLeaf.setTable(leafTableConfig.getTable());
			sourceCodeParamLeaf.setColumns(leafTableConfig.getColumnVOList());
			sourceCodeParamLeaf.setDataGrid(leafTableConfig.getDataGrid());
			sourceCodeParamLeaf.setForm(leafTableConfig.getForm());
			sourceCodeParamLeaf.setColumns(leafTableConfig.getColumnVOList());

			sourceCodeParamLeaf.setForeignTable(catalogTable);
			sourceCodeParamLeaf.setForeignColumn(leafTable.getForeignColumn());
			sourceCodeParamLeaf.setLeafTable(null);
			sourceCodeParamLeaf.setParentColumn(null);
			sourceCodeParamLeaf.setUseRecurseQuery(leafTableConfig.getDataGrid().getUseRecurseQuery());
			sourceCodeParamLeaf.setIsTree(false);
			sourceCodeParamLeaf.setCatalogIsTree(true);

			this.leafTableConfig = sourceCodeParamLeaf;
			this.slaveTablesConfig.add(sourceCodeParamLeaf);
			sourceCodeParams.add(sourceCodeParamLeaf);
		}else if(TablesRelation.MasterAndSlave.equals(tablesRelation)){//主表+从表结构
			Assert.throwz(mainTableConfig != null, String.format("表关系为 主表+从表 时，必须存在 Subtype=%s 的数据表", TableRelationSubtype.MasterTableCaption));
			Assert.throwz(slaveTablesConfig.size() >0 , String.format("表关系为 主表+从表 时，必须存在 Subtype=%s 的数据表", TableRelationSubtype.SlaveTableCaption));
			DataTable masterTable = mainTableConfig.getTable();
			if(masterTable.getForeignColumn() != null) {
				Assert.throwz(masterTable.getForeignTable() != null, String.format("表 %s 设置了外键字段，因此外键表不能为空", masterTable.getTableName()));
			}

			//主表 主从表情况下，主表不能是自递归表。
			SourceCodeParamsBaseTable sourceCodeParamMaster = new SourceCodeParamsBaseTable();
			sourceCodeParamMaster.setTable(masterTable);
			sourceCodeParamMaster.setColumns(mainTableConfig.getColumnVOList());
			sourceCodeParamMaster.setDataGrid(mainTableConfig.getDataGrid());
			sourceCodeParamMaster.setForm(mainTableConfig.getForm());
			sourceCodeParamMaster.setColumns(mainTableConfig.getColumnVOList());

			sourceCodeParamMaster.setForeignColumn(masterTable.getForeignColumn());
			sourceCodeParamMaster.setForeignTable(masterTable.getForeignTable());
			
			sourceCodeParamMaster.setLeafTable(null);
			sourceCodeParamMaster.setParentColumn(null);
			sourceCodeParamMaster.setUseRecurseQuery(false);
			sourceCodeParamMaster.setIsTree(false);

			this.mainTableConfig = sourceCodeParamMaster;
			this.catalogTableConfig = sourceCodeParamMaster;
			sourceCodeParams.add(sourceCodeParamMaster);

			//从表（可是是多个）
			for(PageConfigVO slaveTableConfig : slaveTablesConfig) {
				DataTable slaveTable = slaveTableConfig.getTable();
				Assert.throwz(slaveTable.getForeignColumn() != null, String.format("从表 %s 的外键字段（关联主表的字段）不能为空",slaveTable.getTableName()));
				SourceCodeParamsBaseTable sourceCodeParamSlave = new SourceCodeParamsBaseTable();
				sourceCodeParamSlave.setTable(slaveTableConfig.getTable());
				sourceCodeParamSlave.setColumns(slaveTableConfig.getColumnVOList());
				sourceCodeParamSlave.setDataGrid(slaveTableConfig.getDataGrid());
				sourceCodeParamSlave.setForm(slaveTableConfig.getForm());
				sourceCodeParamSlave.setColumns(slaveTableConfig.getColumnVOList());

				sourceCodeParamSlave.setForeignColumn(slaveTable.getForeignColumn());
				sourceCodeParamSlave.setForeignTable(masterTable);
				sourceCodeParamSlave.setLeafTable(null);
				sourceCodeParamSlave.setParentColumn(null);
				sourceCodeParamSlave.setUseRecurseQuery(false);
				sourceCodeParamSlave.setIsTree(false);

				this.slaveTablesConfig.add(sourceCodeParamSlave);
				sourceCodeParams.add(sourceCodeParamSlave);
			}
		}else{
			throw new HException(String.format("请检查func.id=%d记录的TablesRelation，不能为空",tablesRelation));
		}

		//设置公共变量
		for(SourceCodeParamsBaseTable sourceCodeParam : sourceCodeParams) {
			sourceCodeParam.setProject(getProject());
			sourceCodeParam.setFunc(getFunc());
			sourceCodeParam.setAuthor(getAuthor());
			sourceCodeParam.setNowTime(getNowTime());
			sourceCodeParam.setSysName(getSysName());
		}
	}
	/** -------------------------------------------property get set------------------------------------------------- */

	public Project getProject() {
		return project;
	}
	public void setProject(Project project) {
		this.project = project;
	}

	public Func getFunc() {
		return func;
	}
	public void setFunc(Func func) {
		this.func = func;
	}

	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}

	public String getNowTime() {
		return nowTime;
	}
	public void setNowTime(String nowTime) {
		this.nowTime = nowTime;
	}

	public String getSysName() {
		return sysName;
	}
	public void setSysName(String sysName) {
		this.sysName = sysName;
	}

//	public String getMainFileName() {
//		return mainFileName;
//	}
//
//	public void setMainFileName(String mainFileName) {
//		this.mainFileName = mainFileName;
//	}

	public DataTable getMainTable(){
		if(mainTableConfig == null)return null;
		return mainTableConfig.getTable();
	}
	public SourceCodeParamsBaseTable getMainTableConfig() {
		return mainTableConfig;
	}
	public void setMainTableConfig(SourceCodeParamsBaseTable mainTableConfig) {
		this.mainTableConfig = mainTableConfig;
	}


	public DataTable getCatalogTable(){
		if(catalogTableConfig == null)return null;
		return catalogTableConfig.getTable();
	}
	public SourceCodeParamsBaseTable getCatalogTableConfig() {
		return catalogTableConfig;
	}
	public void setCatalogTableConfig(SourceCodeParamsBaseTable catalogTableConfig) {
		this.catalogTableConfig = catalogTableConfig;
	}
	
//	/**主表（或者目录表）的主表*/
//	public DataTable getParentTable(){
//		if(parentTableConfig == null)return null;
//		return parentTableConfig.getTable();
//	}
//	/**主表（或者目录表）的主表*/
//	public SourceCodeParamsBaseTable getParentTableConfig() {
//		return parentTableConfig;
//	}
//	/**主表（或者目录表）的主表*/
//	public void setParentTableConfig(SourceCodeParamsBaseTable parentTableConfig) {
//		this.parentTableConfig = parentTableConfig;
//	}

	public DataTable getLeafTable(){
		if(leafTableConfig == null)return null;
		return leafTableConfig.getTable();
	}
	public SourceCodeParamsBaseTable getLeafTableConfig() {
		return leafTableConfig;
	}
	public void setLeafTableConfig(SourceCodeParamsBaseTable leafTableConfig) {
		this.leafTableConfig = leafTableConfig;
	}

	public List<SourceCodeParamsBaseTable> getSlaveTablesConfig() {
		return slaveTablesConfig;
	}

	public List<SourceCodeParamsBaseTable> getSourceCodeParams() {
		return sourceCodeParams;
	}


	//	public String getTerminalType() {
//		return terminalType;
//	}
//	public void setTerminalType(String terminalType) {
//		this.terminalType = terminalType;
//	}
	/**
	 * 重点：生成java代码需要根据web页面配置的字段关系，尤其是表单的保存功能，后台代码必须和表单上的字段对应
	 * 思路一：
	 *      根据页面类型，限制表的个数及用途。
	 *      1、带树形结构和表格：最多四个表：TreeCatalogTable,TreeLeafTable,GridMasterTable,GridChildTable,一个表：TreeCatalogTable，两个表：TreeCatalogTable、TreeLeafTable，或者TreeCatalogTable，GridMasterTable，三个表：TreeCatalogTable,TreeLeafTable,GridMasterTable
	 *      2、只有表格：最多3个表：GridMasterTable,GridChildTable1,GridChildTable2
	 *      
	 *      生成代码：
	 *      1、生成Java代码 genJava(dataTable, parentTable, form)
	 *      
	 *思路二：
	 *		更灵活的方式，不限制数据表的个数，根据UITree和UIGrid配置的参数自动判断涉及的表，和生成对应的文件。但是不能完全使用模板的方式，因为模板无法确定要生成哪些文件
	 *		1、java文件和Form表单：根据配置的Dataset，每个Dataset生成一组。但是父子结构的逻辑无法构造。
	 *		2、一个PageLayout生成一个MainPage。根据模板生成。
	 *		
	 *
	 * 采用思路一
	 * --------------------------------------------------------------------------------------------------------------------------------------------------------
	 *      
	 * 1、生成java代码  genJava(Table、Form)，一个PageLayout下的每个Dataset生成一组java文件(pojo,dao,service,controller)
	 * 		genJava(treeCatalogTable, treeCatalogForm)
	 * 		genJava(treeLeafTable, treeLeafForm)
	 * 		genJava(gridMasterTable, gridMasterForm)
	 * 		genJava(gridCatalogTable, gridCatalogForm)
	 * 		genJava(childGridMasterTable, childGridMasterForm)
	 * 		genJava(childGridCatalogTable, childGridCatalogForm)
	 * 
	 * 2、生成主页面代码 genMainPage(Tree，Grid)，一个PageLayout只生成一个主页面代码
	 * 3、生成表单代码   genForm(Form, Table)，一个PageLayout下的每个UIForm生成一个form页面
	 * 
	 * */
	
	
	
}
